//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//********************************************************* 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices; 

namespace Microsoft.TridentWordAddIn.Common
{
    public static class ListViewExtensions
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct HDITEM
        {
            public Int32 mask;
            public Int32 cxy;
            [MarshalAs(UnmanagedType.LPTStr)]
            public String pszText;
            public IntPtr hbm;
            public Int32 cchTextMax;
            public Int32 fmt;
            public Int32 lParam;
            public Int32 iImage;
            public Int32 iOrder;
        };

        // Parameters for ListView-Headers
        public const Int32 HDI_FORMAT = 0x0004;
        public const Int32 HDF_LEFT = 0x0000;
        public const Int32 HDF_STRING = 0x4000;
        public const Int32 HDF_SORTUP = 0x0400;
        public const Int32 HDF_SORTDOWN = 0x0200;
        public const Int32 LVM_GETHEADER = 0x1000 + 31;  // LVM_FIRST + 31
        public const Int32 HDM_GETITEM = 0x1200 + 11;  // HDM_FIRST + 11
        public const Int32 HDM_SETITEM = 0x1200 + 12;  // HDM_FIRST + 12

        [DllImport("user32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", EntryPoint = "SendMessage")]
        private static extern IntPtr SendMessageITEM(IntPtr Handle, Int32 msg, IntPtr wParam, ref HDITEM lParam);

        /// <summary>
        /// Shows the error message.
        /// </summary>
        /// <param name="listview">The listview.</param>
        /// <param name="message">The message.</param>
        public static void ShowErrorMessage(this ListView listView, string message)
        {
            listView.Clear();
            listView.Columns.Clear();
            listView.Columns.Add("Message");
            listView.Columns[0].Width = 255;

            ListViewItem errorItem = new ListViewItem();
            errorItem.ForeColor = Color.Red;
            errorItem.Font = new Font(listView.Font, FontStyle.Italic);
            errorItem.Text = message;
            listView.Items.Add(errorItem);

            listView.Columns[0].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
        }

        /// <summary>
        /// Shows the error message no column.
        /// </summary>
        /// <param name="listview">The listview.</param>
        /// <param name="message">The message.</param>
        public static void ShowErrorMessageNoColumn(this ListView listView, string message)
        {
            listView.Clear();
            listView.Columns.Clear();
            listView.View = View.Tile;
            ListViewItem errorItem = new ListViewItem();
            errorItem.ForeColor = Color.Red;
            errorItem.Font = new Font(listView.Font, FontStyle.Italic);
            errorItem.Text = message;
            listView.Items.Add(errorItem);
        }

        /// <summary>
        /// Adds the columns.
        /// </summary>
        /// <param name="listview">The listview.</param>
        /// <param name="columnHeaders">The column headers.</param>
        public static void AddColumns(this ListView listView, string[] columnHeaders)
        {
            int index = 0;
            int width = listView.Width / columnHeaders.Length;
            if (listView.Columns.Count <= 1)
            {
                listView.Columns.Clear();
                foreach (string name in columnHeaders)
                {
                    listView.Columns.Add(name);
                    listView.Columns[index].Width = width;
                    index++;
                }
            }
        }

        /// <summary>
        /// Groups the specified list view.
        /// </summary>
        /// <param name="listView">The list view.</param>
        /// <param name="groupHeaders">The group headers.</param>
        public static ListViewGroup AddGroup(this ListView listView, string groupHeader)
        {
            ListViewGroup lvGroup = new ListViewGroup(groupHeader);
            listView.Groups.Add(lvGroup);
            return lvGroup;
        }

        /// <summary>
        /// Adds the item.
        /// </summary>
        /// <param name="listView">The list view.</param>
        /// <param name="name">The name.</param>
        /// <param name="values">The values.</param>
        public static ListViewItem AddItem(this ListView listView, string name, string[] values)
        {
            ListViewItem newItem = new ListViewItem(name);
            foreach (string value in values)
            {
                newItem.SubItems.Add(value);
            }

            listView.Items.Add(newItem);
            return newItem;
        }

        /// <summary>
        /// Sets the sort icons.
        /// </summary>
        /// <param name="listView">The list view.</param>
        /// <param name="previouslySortedColumn">The previously sorted column.</param>
        /// <param name="newSortColumn">The new sort column.</param>
        public static void SetSortIcon(this ListView listView, ListViewSorting lvSorting, ref int previouslySortedColumn, int newSortColumn)
        {
            IntPtr hHeader = SendMessage(listView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
            IntPtr newColumn = new IntPtr(newSortColumn);
            IntPtr prevColumn = new IntPtr(previouslySortedColumn);
            HDITEM hdItem;
            IntPtr rtn;

            // Only update the previous item if it existed and if it was a different one.
            if (previouslySortedColumn != -1 && previouslySortedColumn != newSortColumn)
            {
                // Clear icon from the previous column.
                hdItem = new HDITEM();
                hdItem.mask = HDI_FORMAT;
                rtn = SendMessageITEM(hHeader, HDM_GETITEM, prevColumn, ref hdItem);
                hdItem.fmt &= ~HDF_SORTDOWN & ~HDF_SORTUP;
                rtn = SendMessageITEM(hHeader, HDM_SETITEM, prevColumn, ref hdItem);
            }

            // Set icon on the new column.
            hdItem = new HDITEM();
            hdItem.mask = HDI_FORMAT;
            rtn = SendMessageITEM(hHeader, HDM_GETITEM, newColumn, ref hdItem);
            if (lvSorting.SortDirection == SortOrder.Ascending)
            {
                hdItem.fmt &= ~HDF_SORTDOWN;
                hdItem.fmt |= HDF_SORTUP;
            }
            else
            {
                hdItem.fmt &= ~HDF_SORTUP;
                hdItem.fmt |= HDF_SORTDOWN;
            }
            rtn = SendMessageITEM(hHeader, HDM_SETITEM, newColumn, ref hdItem);
            previouslySortedColumn = newSortColumn;
        }
    }
}
